export const fibonacciIterative = (number) => {
  if (number < 1) {
    return 0;
  } else if (number <= 2) {
    return 1;
  } else {
    let fibPre1 = 1;
    let fibPre2 = 1;
    let fibN = 2;

    for (let i = 3; i < number; i++) {
      fibPre1 = fibPre2;
      fibPre2 = fibN;
      fibN = fibPre1 + fibPre2;
    }
    return fibN;
  }
};

export const fibonacciRecursiveNormal = (number: number) => {
  const numHandle = Math.floor(number);

  if (numHandle === 0) {
    return 0;
  } else if (numHandle === 1 || numHandle === 2) {
    return 1;
  } else if (numHandle > 2) {
    return fibonacciRecursiveNormal(numHandle - 1) + fibonacciRecursiveNormal(numHandle - 2);
  } else {
    return undefined;
  }
};

export const fibonacciRecursiveCache = (number: number) => {
  const numHandle = Math.floor(number);
  const memo: number[] = [0, 1, 1];
  
  const fibonacci = (number) => {
    if (memo[number] !== undefined) {
      return memo[number];
    } else {
      if (number < 0) {
        return undefined;
      } else {
        let result = fibonacci(number -1) + fibonacci(number - 2);
        memo[number] = result;
        return result;
      }
    }
  };

  return fibonacci(numHandle);
};

const fibonacciRecursiveTail = (number: number, rPre1 = 0, rPre2 = 1) => {
  const numHandle = Math.floor(number);
  
  if (numHandle === 0) {
    return rPre1;
  } else if (numHandle === 1) {
    return rPre2;
  } else {
    return fibonacciRecursiveTail(number - 1, rPre2, rPre1 + rPre2);
  }
};

export const fibonacciRecursive = {
  fibonacciRecursiveCache,
  fibonacciRecursiveTail: (number) => {
    return fibonacciRecursiveTail(number);
  },
  fibonacciRecursiveNormal,
};
